package com.cssw.fyzb.core.eao.video;

import com.alibaba.fastjson.JSON;
import com.cssw.fyzb.core.es.EsClient;
import com.cssw.fyzb.core.model.eos.VideoEo;
import com.cssw.fyzb.core.model.eos.VideoLikeEo;
import com.cssw.fyzb.core.util.DateUtil;
import com.cssw.fyzb.core.util.StringUtil;
import com.ydn.dbframe.plugin.activerecord.Page;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.index.query.BoolQueryBuilder;
import org.elasticsearch.index.query.QueryBuilders;
import org.elasticsearch.index.reindex.BulkByScrollResponse;
import org.elasticsearch.index.reindex.DeleteByQueryAction;
import org.elasticsearch.script.Script;
import org.elasticsearch.search.SearchHit;
import org.elasticsearch.search.sort.ScriptSortBuilder;
import org.elasticsearch.search.sort.SortBuilders;
import org.elasticsearch.search.sort.SortOrder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.Date;
import java.util.List;

/**
 * @author Feng Chen
 */
@Component
public class VideoEaoImpl implements VideoEao {

    @Autowired
    private EsClient esClient;

    @Override
    public void save(
            Long userId, Long vedioId, String title, String media, String cover, String city, String lat, String lng, Integer createTime
            , Integer musicId, String musicTitle, String musicAuthor, String musicImgUrl, String musicLength, String musicFileUrl,
            String musicFormat, String anyway, Integer classId) {
        VideoEo videoEo = new VideoEo();
        Date ctime = new Date(Long.valueOf(createTime) * 1000);
//        Date ctime = new Date(Long.valueOf(createTime) * 1000);

        videoEo.setUserId(userId);
        videoEo.setVedioId(vedioId);
        videoEo.setTitle(title);
        videoEo.setMedia(media);
        videoEo.setCover(cover);
        videoEo.setCity(city);
        if (StringUtil.isEmpty(lat)){
            lat = "0";
        }
        if (StringUtil.isEmpty(lng)){
            lng = "0";
        }
        videoEo.setLoc(String.format("%s,%s", lat, lng));
        videoEo.setCreateTime(DateUtil.format(ctime));
        videoEo.setMusicId(musicId);
        videoEo.setMusicTitle(musicTitle);
        videoEo.setMusicAuthor(musicAuthor);
        videoEo.setMusicImgUrl(musicImgUrl);
        videoEo.setMusicLength(musicLength);
        videoEo.setMusicFileUrl(musicFileUrl);
        videoEo.setMusicFormat(musicFormat);
        videoEo.setAnyway(anyway);
        videoEo.setClassId(classId);
        esClient.getClient()
                .prepareIndex(route("fyzb_video",ctime), route("fyzb_video",ctime))
                .setSource(JSON.parseObject(JSON.toJSONString(videoEo)))
                .get()
        ;
    }

    @Override
    public Page<VideoEo> pageByUserIds(int pageNumber, int pageSize, Long... userIds) {
        SearchResponse response = esClient.getClient()
                .prepareSearch(route("fyzb_video"))
                .setQuery(
                        QueryBuilders.boolQuery().filter(
                                QueryBuilders.termsQuery("userId", userIds)
                        )
                )
                .setFrom(pageNumber * (pageSize - 1))
                .setSize(pageSize)
                .addSort(
                        SortBuilders.fieldSort("createTime").order(SortOrder.DESC)
                ).get();

        return toPage(response, pageNumber, pageSize);
    }

    @Override
    public Page<VideoEo> pageByCity(int pageNumber, int pageSize, String city, String lat, String lng) {
        SearchResponse response = esClient.getClient()
                .prepareSearch(route("fyzb_video"))
                .setQuery(
                        QueryBuilders.boolQuery().filter(
                                QueryBuilders.termQuery("city", city)
                        )
                )
                .setFrom(pageNumber * (pageSize - 1))
                .setSize(pageSize)
                .addSort(
                        SortBuilders.geoDistanceSort("loc", Double.valueOf(lat), Double.valueOf(lng))
                                .order(SortOrder.ASC)
                )
                .addSort(
                        SortBuilders.fieldSort("createTime").order(SortOrder.DESC)
                ).get();

        return toPage(response, pageNumber, pageSize);
    }

    @Override
    public Page<VideoEo> pageByFound(int pageNumber, int pageSize) {
        SearchResponse response = esClient.getClient()
                .prepareSearch(route("fyzb_video"))
                .setQuery(
                        QueryBuilders.rangeQuery("createTime").gt(startTime()).lte(endTime())
                )
                .setFrom(pageNumber * (pageSize - 1))
                .setSize(pageSize)
                .addSort(
                        SortBuilders.scriptSort(new Script("Math.random()"), ScriptSortBuilder.ScriptSortType.NUMBER)
                                .order(SortOrder.DESC)
                )
                .get();

        return toPage(response, pageNumber, pageSize);
    }


    @Override
    public long deleteById(Long videoId, Date createDate) {
        BoolQueryBuilder queryBuilder = QueryBuilders.boolQuery();
        queryBuilder.filter().add(QueryBuilders.termQuery("vedioId", videoId));

        BulkByScrollResponse response = DeleteByQueryAction.INSTANCE.newRequestBuilder(esClient.getClient())
                .filter(queryBuilder)
                .source(route("fyzb_video", createDate))
                .get();

        return response.getDeleted();
    }


    @Override
    public Page<VideoEo> page(int pageNumber, int pageSize) {
        SearchResponse response = esClient.getClient()
                .prepareSearch(route("fyzb_video"))
                .setFrom(pageNumber * (pageSize - 1))
                .setSize(pageSize)
                .addSort(
                        SortBuilders.fieldSort("createTime").order(SortOrder.DESC)
                ).get();

        return toPage(response, pageNumber, pageSize);
    }

    // SECTION : INNER HELPER

    private String route(String index, Date date) {
        return new StringBuilder()
                .append(index)
                .append("_")
                .append(DateUtil.getMonth(date))
                .toString();
    }

    private String[] route(String index) {
        List<String> idxs = new ArrayList<>();
        for (String month : DateUtil.getMonth(2)) {
            idxs.add(
                    new StringBuilder()
                            .append(index)
                            .append("_")
                            .append(month)
                            .toString()
            );
        }
        return idxs.toArray(new String[idxs.size()]);
    }

    private Page<VideoEo> toPage(SearchResponse response, int pageNumber, int pageSize) {
        Page<VideoEo> page = new Page<>();
        int count = (int) response.getHits().totalHits;
        page.setTotalPage((int) Math.ceil(count * 1.0 / pageSize));
        page.setTotalRow(count);
        page.setPageNumber(pageNumber);
        page.setPageSize(pageSize);
        List<VideoEo> list = new ArrayList<>();
        for (SearchHit hit : response.getHits()) {
            list.add(JSON.parseObject(JSON.toJSONString(hit.getSourceAsMap()), VideoEo.class));
        }
        page.setList(list);
        return page;
    }

    private String endTime() {
        return DateUtil.format(new Date());
    }

    private String startTime() {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(new Date());
        calendar.set(Calendar.DAY_OF_YEAR, calendar.get(Calendar.DAY_OF_YEAR) - 90);
        return DateUtil.format(calendar.getTime());
    }

}
